#include "storage/disk_manager.h"
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <sys/stat.h>

namespace boltDB {
DiskManager::DiskManager(const std::string &db_file):file_name_(db_file) {
  std::string::size_type n = file_name_.rfind('.');
  if (n == std::string::npos) {
    return;
  }
  std::scoped_lock scoped_db_io_latch(db_io_latch_);
  db_io_.open(db_file, std::ios::binary | std::ios::in | std::ios::out);
  // 文件不存在
  if (!db_io_.is_open()) {
    db_io_.clear();
    db_io_.open(db_file, std::ios::binary | std::ios::trunc | std::ios::out |
                             std::ios::in);
    if (!db_io_.is_open()) {
        std::invalid_argument("can't open db file");
    }
  }
}
void DiskManager::ShutDown() { 
    std::scoped_lock scoped_db_io_locker(db_io_latch_);
    db_io_.close();  
}

void DiskManager::WritePage(page_id_t page_id, const char *page_data) {
  std::scoped_lock scoped_db_io_latch(db_io_latch_);
  size_t offset = static_cast<size_t>(page_id) * BOLTDB_PAGE_SIZE;
  // 找到偏移量开始写入
//   num_writes_ += 1;
  db_io_.seekp(offset);
  db_io_.write(page_data, BOLTDB_PAGE_SIZE);
  if (db_io_.bad()) {
    // LOG_DEBUG("I/O error while writing");
    return;
  }
  // 刷新缓冲区
  db_io_.flush();
}

void DiskManager::ReadPage(page_id_t page_id, char *page_data) {
  std::scoped_lock scoped_db_io_latch(db_io_latch_);
  int offset = page_id * BOLTDB_PAGE_SIZE;
  // 检查页面是否包含在数据库文件中
  if (offset > GetFileSize(file_name_)) {
    // LOG_DEBUG("I/O error reading past end of file");
    std::cerr << "I/O error while reading" << std::endl;
  } else {
    // 移动文件偏移区读
    db_io_.seekp(offset);
    db_io_.read(page_data, BOLTDB_PAGE_SIZE);
    if (db_io_.bad()) {
    //   LOG_DEBUG("I/O error while reading");
      return;
    }
    // 如果读取的内容少于一页
    int read_count = db_io_.gcount();
    if (read_count < BOLTDB_PAGE_SIZE) {
    //   LOG_DEBUG("Read less than a page");
      db_io_.clear();
      // std::cerr << "Read less than a page" << std::endl;
      memset(page_data + read_count, 0, BOLTDB_PAGE_SIZE - read_count);
    }
  }
}

auto DiskManager::GetFileSize(const std::string &file_name) -> int {
  struct stat stat_buf;
  int rc = stat(file_name.c_str(), &stat_buf);
  return rc == 0 ? static_cast<int>(stat_buf.st_size) : -1;
}

}  // namespace boltDB